Overview

The Structured Query Language (SQL) is a language designed for the management of relational databases. SQL injections vulnerabilities occur when user input is passed unsanitised to an SQL query and allow an attacker to alter the queries that an application sends to its database. This may enable the attacker to view data which they usually shouldn't have access to, edit this data arbitrarily, or modify the actual database in ways that they shouldn't be able to.

Types of SQL Injection

There are three main types of SQL injections:

  1. In-band - the vulnerable application provides the query's result with the application-returned value

    • Error-based injections - information is extracted through error messages returned by the vulnerable application.
    • Union-based injections - these allow an adversary to concatenate the results of a malicious query to those of a legitimate one.
  2. Out-of-band - the results from the attack are exfiltrated using a different channel than the one the query was issued through such as through an HTTP connection for sending results to a different web server or DNS tunneling

    • It requires specific extenstions to be enabled in the database management software.
    • The targated database server must be able to send outbound network requests without any restrictions.
  3. Blind (Inferential) - they rely on changes in the behaviour of the database or application in order to extract information, since the actual data isn't sent back to the attacker

    • These are detected through time delays or boolean conditions.

Testing for SQL Injection

Testing for SQL injections is fairly straightforward but can be an onerous task. It constitutes inserting a single quote and then a payload such as ' SQL PAYLOAD into any user input field and observing the subsequent behaviour.

Tip

It comes in handy to append comment sequences such as -- - to your payloads so that any parts of the query which come after the injection point will not interfere with the injection. This works on all database engines.

If the result from the query is directly embedded into the web page, then this is the simplest and most powerful type of in-band SQL injection because it provides us with a direct way to see the output of the query and exfiltrate data. When this type of SQL injection is present, one can use Union Injection to easily obtain information from the database.

Example: Simple SQL Injection

We can use this PortSwigger lab to showcase a simple SQL injection. We notice that we can filter our search using one of the buttons on the home page under "Refine your search".

Clicking on one of the filter buttons produces a GET request and we can try to manipulate the category parameter.

Indeed, using the payload ' or 1=1 -- - as the value for category reveals some products which were hidden before.

Blind SQL Injection

Blind SQL injection occurs when an application is vulnerable to SQL injection, but the response page does not include the queried data or any specific database errors.

The first way to test for these is to use boolean conditions via the AND operator. If we suspect that a field is vulnerable to SQL injection, then we can first try the following payload:

legitimate value' and 1=1

This should result in no errors or odd behaviour regardless of any SQL injection that is present because 1=1 is always true and so the output depends only on the first part of the query. Next, we change the condition so that is always false:

legitimate value' and 1=2

This query will always fail if the application is vulnerable to SQL injection, since the condition 1=2 is always false. If we now observe a change in the behaviour of the application as compared to when the condition was 1=1, we can be fairly certain that the target is vulnerable to blind SQL injection.

The second way to test for blind SQL injections is by using time delays. The functions which trigger time delays are different across the various database engines, but the basic premise is the same - we send a payload which should cause a certain delay and then we check if the response time is close to the delay we specified. Following is a list of the various delay-causing payloads one can use with different database engines.

DatabaseFunctionExample PayloadNote
MySQLsleep(seconds)1' + sleep(5)
1' and sleep(5)
1' && sleep(5)
1' | sleep(5)
PostgreSQLpg_sleep(seconds)1' || pg_sleep(5)Can only be done with the || operator.
MSSQLWAITFOR DELAY 'hours:minutes:seconds'1' WAITFOR DELAY '0:0:10'Notice the lack of a logical or any other operator.
Oracledbms_pipe.receive_message((random string),seconds)dbms_pipe.receive_message(('a'),10)

Note: Manual Exploitation of Blind SQL Injection

While obtaining data by manually exploiting blind SQL injection is possible, the process is very arduous and basically consists of asking a myriad yes-or-no questions about the data in an attempt to guess what it is.

Automation

sqlmap is the go-to tool for automating SQL injection detection and exploitation.

Note

While very useful, sqlmap is far from stealthy and generates a lot of traffic.

Its basic syntax is as follows:

sqlmap -u <full URL> -p <parameter>

The full URL is the exact URL of the web page we are testing for injection, including any parameters that may be in it. The parameter argument specifies the parameter we want to test for injection.

One of its best features is the ability to specify a request from a file. This is particularly useful because one can save an intercepted request through BurpSuite and then pass it to sqlmap which will automatically detect any possible injection points in it.

To pass the file to sqlmap we use the -r option:

sqlmap -r <file path>